package cmpe273.proj1.model;

import java.util.ArrayList;
import java.util.List;

import org.json.JSONException;
import org.json.JSONObject;

import cmpe273.proj1.utilities.Utilities;

public class Instructor extends Person {
	//public constants
	public static int MAX_LENGTH_DEPARTMENT = 40;
	public static int MAX_LENGTH_INSTRUCTORID = 11;
	public static int MAX_LENGTH_OFFICEHOURS = 40;
	public static int MAX_LENGTH_OFFICELOCATION = 40;

	//private members
	private Long id;
	private String instructorId;
	private String department;
	private String officeHours;
	private String officeLocation;
	private List<Course> taughtCourses;

	//constructors
	public Instructor() {
		super();
		this.id = null;
		this.instructorId = "";
		this.department = "";
		this.officeHours = "";
		this.officeLocation = "";
		this.taughtCourses = new ArrayList<Course>();
	}

	public Instructor(Long id, String instructorId, String department, String officeHours, String officeLocation, Person person, List<Course> taughtCourses) {
		super(person);
		this.id = id;
		this.instructorId = instructorId == null ? "" : instructorId;
		this.department = department == null ? "" : department;
		this.officeHours = officeHours == null ? "" : officeHours;
		this.officeLocation = officeLocation == null ? "" : officeLocation;
		this.taughtCourses = taughtCourses == null ? new ArrayList<Course>() : taughtCourses;
	}

	//accessors
	public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
    	
	public String getInstructorId() {
		return instructorId;
	}
	
	public void setInstructorId(String instructorId) {
		this.instructorId = instructorId;
	}
	
	public String getDepartment() {
		return department;
	}
	
	public void setDepartment(String department) {
		this.department = department;
	}
	
	public String getOfficeHours() {
		return officeHours;
	}
	
	public void setOfficeHours(String officeHours) {
		this.officeHours = officeHours;
	}
	
	public String getOfficeLocation() {
		return officeLocation;
	}
	
	public void setOfficeLocation(String officeLocation) {
		this.officeLocation = officeLocation;
	}
	
	public List<Course> getTaughtCourses() {
		return taughtCourses;
	}
	
	public void setTaughtCourses(List<Course> taughtCourses) {
		this.taughtCourses = taughtCourses;
	}

	//json utility
	public boolean loadInstructor(JSONObject jsonObj) {
		try {
			if(!super.loadPerson(jsonObj))
				return false;

			this.instructorId = jsonObj.getString("instructorId");
			this.department = jsonObj.getString("department");
			this.officeHours = jsonObj.getString("officeHours");
			this.officeLocation = jsonObj.getString("officeLocation");
			this.taughtCourses = Course.toCourseList(jsonObj.getJSONArray("taughtCourses"));
		} catch (JSONException e) {
			System.out.println("Invalid Instructor jsonObj: " + jsonObj.toString());
			return false;
		}
		return true;
	}

	public boolean loadInstructor(String jsonString) {
		try {
			JSONObject obj = new JSONObject(jsonString);

			return loadInstructor(obj);
		} catch (JSONException e) {
			System.out.println("Invalid Instructor jsonString: " + jsonString);
			return false;
		}
	}

	public String toJsonString() {
		String ret  = "{\"instructorId\":\"" + instructorId + "\", \"department\":\"" + department + "\", \"officeHours\":\"" + officeHours + "\", " + super.toPartialJsonString() + ", \"taughtCourses\":\"" + Course.toJsonArray(taughtCourses) + "\"}";
		return ret;
	}

	public JSONObject toJsonObject()
	{
		return Utilities.toJsonObject(this.toJsonString());
	}
	
	//validation utilities
	public String validate() {
		StringBuilder sb = new StringBuilder();
		
		if(instructorId.length() != MAX_LENGTH_INSTRUCTORID)
			sb.append(String.format(Utilities.STRING_LENGTH_ERROR_NOTEQUAL, "Instructor ID", MAX_LENGTH_INSTRUCTORID));
		if(department.length() > MAX_LENGTH_DEPARTMENT)
			sb.append(String.format(Utilities.STRING_LENGTH_ERROR, "Department", MAX_LENGTH_DEPARTMENT));
		if(officeHours.length() > MAX_LENGTH_OFFICEHOURS)
			sb.append(String.format(Utilities.STRING_LENGTH_ERROR, "Office hours", MAX_LENGTH_OFFICEHOURS));
		if(officeLocation.length() > MAX_LENGTH_OFFICELOCATION)
			sb.append(String.format(Utilities.STRING_LENGTH_ERROR, "Office location", MAX_LENGTH_OFFICELOCATION));
		
		if(!Person.validId(instructorId))
			sb.append(String.format(Utilities.ID_FORMAT_ERROR));
		
		sb.append(super.validate());
		return sb.toString();
	}

	//Serializable Overrides
	/**
	 * The user ID is unique for each Instructor. So this should compare Instructor by ID only.
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object other) {
		return (other instanceof Instructor) && (id != null)
				? id.equals(((Instructor) other).id)
						: (other == this);
	}

	/**
	 * The user ID is unique for each Instructor. So Instructor with same ID should return same hashcode.
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		return (id != null) 
				? (this.getClass().hashCode() + id.hashCode()) 
						: super.hashCode();
	}

	/**
	 * Returns the String representation of this Instructor. Not required, it just pleases reading logs.
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return String.format("Instructor[id=%d,instructorId=%s,department=%s,officeHours=%s,officeLocation=%s,numTaughtCourses=%d,super=%s]", 
				id, instructorId, department, officeHours, officeLocation, taughtCourses.size(), super.toString());
	}
}
